<template>
  <div style="display: flex; align-items:flex-start ;background-color: #EBEDF5;">
    <div class="left-main">
      <el-image
      class="image-head"
      :src="headUrl"
      :fit="'contain'"
      >
      </el-image>
      <div style="  width: 88%; height: 1%; margin:25% 0% 0% 6%">
        <hr style=" border-color:rgb(177, 177, 177);  "/>
      </div>

      <div @click="selectController(index)"
      :style="selectedImageIndex==index ? 'border: 3px solid #79C419;' : ''"
       class="image-item" v-for="(p,index) in urlData" :key="index">
          <el-badge :value="p.allUnreadMsg" :hidden="p.allUnreadMsg<=0" >
            <el-image
            style="  width: 50%; height: 50%; margin:23% 0% 0% 25% "
            :src="p.url">
          </el-image>
       </el-badge>
      </div>
      
    </div>
    <div class="right-main">
        <router-view/>
    </div>

    <el-dialog :visible.sync="dialogVisible" width="45%">
       <el-tabs :tab-position="'left'" style="height: 100%;">
    <el-tab-pane label="个人信息">
        <div style="display: flex; ">
            <div :style="{backgroundImage:`url(${this.headUrl})`}" class="search-data-head-image" />
             <div class="search-data-head-name">
                <br/>
                <div style="margin-bottom: 1%; font-weight:bold; font-size: 1.5vw; color:black;">{{$store.state.userName}}</div><br/><br/>
                <span style="font-size: 1.2vw;">uid：{{$store.state.userUid}}</span>
            </div>
        </div>
      </el-tab-pane>
    <el-tab-pane label="修改个人信息">
      新头像：
      <el-upload
      accept=".jpg, .png"
      action="null"
      :multiple="false"
      list-type="picture-card"
      :on-change="fileChange"
      :file-list="updateHeadImage">
        <i slot="default" class="el-icon-plus"></i>
        <div slot="file" slot-scope="{file}">
          <img
            class="el-upload-list__item-thumbnail"
            :src="file.url" alt=""
          >
        </div>
      </el-upload><br/>
    新昵称:
    <el-input style=" width:70%;  margin-left:2%; "  maxlength=8 v-model="newUserName"></el-input>
    <div @click="updateHeadImageOrName" class="update-info-button">确认修改</div>
  </el-tab-pane>

    <el-tab-pane label="修改密码">
    旧密码:
    <el-input style=" width:70%;  margin-left:2%; "  maxlength=20 v-model="oldPassword"></el-input><br/><br/>
    新密码:
    <el-input style=" width:70%;  margin-left:2%; "  maxlength=20 v-model="newPassword"></el-input>
    <div @click="updatePassword" class="update-info-button">确认修改</div>
    </el-tab-pane>

    <el-tab-pane label="注销账号&退出登录">
      <div @click="deleteAccount" class="update-info-button" style="background-color: #d74835;">注销账号</div>
      <div @click="logOut" class="update-info-button">退出登录</div>
      </el-tab-pane>

  </el-tabs>
        <div style="height: 5vh" />
    </el-dialog>

  </div>
</template>

<script>
import callbackMapping from "../websocket/CallbackMapping"
import axios from 'axios'
export default {
  name:'HomePage',
  data(){
    return{
      socket:null, // socket连接对象引用
      updateHeadImage:[],
      dialogVisible:false, 
      newUserName:'',
      oldPassword:'',
      newPassword:'',
      headUrl:'', // 头像
    }
  },
    computed: {
      // 计算属性来获取 Vuex 状态,data中无法实时监控vueX的变化
      urlData() {
        return [{url:require('@/assets/msg.png'),allUnreadMsg:this.$store.state.allUnreadMsg},{url:require('@/assets/friend.png'),allUnreadMsg:this.$store.state.addFriendMsg},
      {url:require('@/assets/group.png'),allUnreadMsg:this.$store.state.addGroupMsg},{url:require('@/assets/util.png'),allUnreadMsg:0}];
      },
      // 主页左侧选择菜单的下标
      selectedImageIndex(){
        return this.$store.state.selectedImageIndex;
      }
    },
    watch: {
    dialogVisible(newVal, oldVal) {
      if (!newVal && oldVal) {
        // 当 dialogVisible 从 true 变为 false时将内容都置空
        this.oldPassword = '';
        this.newPassword = '';
        this.newUserName='';
        this.updateHeadImage=[];
      }
    }
  },
  created(){
    // 发送请求
      axios.get('/accountNumbers/init',{
        headers: {
        'Content-Type': 'application/x-protobuf', // 加上protobuf需要得请求头
        'Authorization': localStorage.getItem('token') // 给上token
        },
        responseType: 'arraybuffer',
      }).then(res=>{
        // 将收到的数据转为protobuf对象
        const proto=this.$protobufClass.PackageInfo.deserializeBinary(new Uint8Array(res.data)).toObject();
        
        // 验证登录结果
        if(proto.code==200){
            let headImage=proto.init.headimage
            if(headImage.startsWith('/9j/')){
              this.headUrl=`data:image/jpg;base64,${headImage}`
            }else if(headImage.startsWith('iVBOR')){
              this.headUrl=`data:image/png;base64,${headImage}`
            }else{
              console.log("图片格式异常") 
            }

            let chatData=proto.init.chatlistList
            for (let i = 0; i < chatData.length; i++){
              chatData[i].headimage=this.$webSocketTools.base64ToImage(chatData[i].headimage)
            }

            proto.init.headimage=this.headUrl;
            proto.init.chatlistList=chatData;
          // 初始化数据写入VueX
          // 需要从VueX中拿的记得在这里调用完初始化数据后再赋值
          this.$store.commit('HTTP_INIT_DATA',proto);
        }else{
           this.$message({
                  message: proto.msg,
                  type: 'error'
                });
        }
      })
      .catch((error) => {
        console.log(error)
          this.$message({
                message: '失败了哦!',
                type: 'error'
              });
          error=this.$protobufClass.PackageInfo.deserializeBinary(new Uint8Array(error)).toObject();
          console.log(error);

        });
  },
  methods:{
    updateHeadImageOrName(){ 
      if(this.newUserName.trim()=="" && this.updateHeadImage.length===0){
        this.$message({
          message: '更新内容不能全为空',
          type: 'warning'
        });
        return
      }
       if(this.newUserName.trim()==this.$store.state.userName){
        this.$message({
          message: '新昵称不能和旧的一样哦',
          type: 'warning'
        });
        return
      }
      // 基本数据
      let proto = new this.$protobufClass.PackageInfo();
      let accountNumber= new this.$accountNumber.AccountNumber();
      accountNumber.setName(this.newUserName);  

      if(this.updateHeadImage.length===0){
        proto.setAccountnumber(accountNumber);
        proto=proto.serializeBinary();
        axios.post("/accountNumbers/updateHeadImageOrName",proto,{
          headers:{
            'Content-Type':'application/x-protobuf',
            'Authorization':localStorage.getItem("token")
          },
          responseType:"arraybuffer"
        }).then(res=>{
          const proto=this.$protobufClass.PackageInfo.deserializeBinary(new Uint8Array(res.data)).toObject();
          if(proto.code==200){
            this.$message({
                message:"修改成功",
                type:"success"
            })
            setTimeout(() => {
              location.reload(); // 成功后等待1秒再刷新页面
            }, 1000); // 成功后刷新一下页面获取新数据
          }else{
            this.$message({
              message:proto.msg,
              type:"error"
            })
          }

        }).catch(err=>{
            this.$message({
            message:err,
            type:"error"
          })
        })
      }else{
        const reader = new FileReader();
        // 这个是异步的，异步将file对象转为base64字符串，完成后调用下面的onload方法
        reader.readAsDataURL(this.updateHeadImage[0].raw);
        // 所有的操作都要在这里进行，因为在外面的话可能异步转换操作还没完时就执行了
        reader.onload = () => {
          // 填充图片
          accountNumber.setImage(reader.result);
          proto.setAccountnumber(accountNumber);
          proto=proto.serializeBinary();
          axios.post("/accountNumbers/updateHeadImageOrName",proto,{
            headers:{
              'Content-Type':'application/x-protobuf',
              'Authorization':localStorage.getItem("token")
            },
            responseType:"arraybuffer"
          }).then(res=>{
            const proto=this.$protobufClass.PackageInfo.deserializeBinary(new Uint8Array(res.data)).toObject();
            if(proto.code==200){
              this.$message({
                message:"修改成功",
                type:"success"
              })
                setTimeout(() => {
                  location.reload(); // 成功后等待1秒再刷新页面
                }, 1000); // 成功后刷新一下页面获取新数据
            }else{
              this.$message({
                message:proto.msg,
                type:"error"
              })
            }

          }).catch(err=>{
              this.$message({
              message:err,
              type:"error"
            })
          })
        };  
    }
  
    },
    updatePassword(){
      if((this.newPassword.trim() == '' && this.oldPassword.trim() == '')
      || this.newPassword.trim()==this.oldPassword.trim()){
          this.$message({
                  message: '两个密码都不可为空或相同',
                  type: 'warning'
                });
      }else{
        let password=new this.$protobufClass.PackageInfo();
        let data=new this.$accountNumber.AccountNumber();
        data.setPassword(this.oldPassword);
        data.setNewpassword(this.newPassword);
        password.setAccountnumber(data);
        password=password.serializeBinary();
        axios.post("/accountNumbers/updatePassword",password,{
          headers:{
            'Content-Type':'application/x-protobuf',
            "Authorization":localStorage.getItem("token")
          },
          responseType:"arraybuffer"
        }).then(res=>{
          const proto=this.$protobufClass.PackageInfo.deserializeBinary(new Uint8Array(res.data)).toObject();
          if(proto.code==200){
            this.dialogVisible=!this.dialogVisible
              this.$message({
                message:"修改成功！",
                type:"success"
              })
          }else{
            this.$message({
              message:proto.msg,
              type:"error"
            })
          }

        }).catch(err=>{
            this.$message({
            message:err,
            type:"error"
          })
        })
      }
    },
    // 退出登录
    logOut(){
      localStorage.removeItem("token")
      localStorage.removeItem("automaticLogin")
      sessionStorage.removeItem("sessionAutomaticLogin")
      location.reload()
    },
    // 注销账号
    deleteAccount(){

        this.$confirm('此操作将彻底注销该账号, 是否继续?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          // 点击确定就会到这里执行注销接口
          axios.get('/accountNumbers/deleteAccount',{
            headers:{
              'Authorization':localStorage.getItem("token"),
            },
            responseType:'arraybuffer'
          }).then(res=>{
            let proto=this.$protobufClass.PackageInfo.deserializeBinary(new Uint8Array(res.data)).toObject();
            if(proto.code==200){
              localStorage.removeItem("token")
              localStorage.removeItem("automaticLogin")
              sessionStorage.removeItem("sessionAutomaticLogin")
              location.reload()
            }else{
              this.$message({
              message:proto.msg,
              type:"error"
            })
            }
          }).catch(err=>{
            this.$message({
              message:err,
              type:"error"
            })
          })
        // 点击取消就什么都不会发生,只提示一下
        }).catch(() => {
          this.$message({
            type: 'info',
            message: '注销操作已取消'
          });          
        });
    },
      // 这里检测到改变后直接存储新图片文件
      fileChange(file){
           let fileType =file.raw.type === 'image/jpeg' || file.raw.type==='image/png'
          let size= file.size/1024<800
          if(fileType && size){
             this.updateHeadImage=[file];
              // 在这里组装数据并发送
          }else{
              this.$message({
                  message:'图片大小超出800kb或格式不为png、jpg格式',
                  type:'error'
              })
          }
      },
 
    // 选择控制器，根据选择的元素来跳转展示对应路由组件以及样式渲染
      selectController(index){
        // 扩展信息直接调用即可
        if(index==3){
          this.dialogVisible=!this.dialogVisible
        }
        // 如果原本就是这个组件，继续点则除了上面的扩展信息以外其他功能不做处理
        if(index!=this.selectedImageIndex){ 
          // 只要点击就改变选中样式
          this.$store.commit("UPDATE_HOME_INDEX",index)
          // 只要当前路由不是要跳转的路由并且选中了它，则跳转，否则不动
          if(index==0 && this.$route.name!="chat"){
            this.$router.push({name:"chat"});
          }else if(index==1 && this.$route.name!="frienndList"){
            this.$router.push({name:"frienndList"});
          }else if(index==2 && this.$route.name!="groupList"){
            this.$router.push({name:"groupList"});
          }
          
        }
      }
  },
  beforeDestroy() {
  // 在组件销毁前关闭WebSocket连接
  if (this.socket) {
      this.socket.close();
      console.log("已回收资源")
  }
},
  mounted(){ // 连接websocket
    // 查看浏览器是否支持websocket
    if(window.WebSocket){
      // 发起连接请求,并将结果赋值给vueX中的socket对象
      this.$store.commit("WEB_SOCKET",new WebSocket("ws://127.0.0.1:7000/ws"))
      this.socket=this.$store.state.socket //连接后将对象交给这里的socket，后面就不用写这么长了

      // WebSocket连接建立成功的处理函数
      this.socket.onopen = () => {
        // 设置数据类型，非常重要，如果没有就收不到数据了
        this.socket.binaryType = "arraybuffer"
        console.log('WebSocket连接已建立');
        // 执行一个默认请求，绑定该连接到后端集合中
        let proto =new this.$protobufClass.PackageInfo();
        proto.setToken(localStorage.getItem("token"));
        proto.setCallbackid(1); // 后端的处理事件id
        proto=proto.serializeBinary();
        this.socket.send(proto)
      };

      // 读收到的数据，用箭头函数就不会影响到this
      this.socket.onmessage=(ev)=>{
        const res = this.$protobufClass.PackageInfo.deserializeBinary(new Uint8Array(ev.data)).toObject();
        // 这里紧挨着的两个回调第一个是用外部方法处理，第二个是直接用回调方法处理。
        // 第一个种好处是可以标准化处理，类似拦截器。第二种就是各自独有的了
        if(res.callbackid!=0){ // 如果收到的是需要这边处理的请求,则渲染进页面让用户处理
          callbackMapping[res.callbackid](this,res) // 记得传入this,否则无法访问vueX
          // 如果没有单独任务就结束
          if(res.taskid==0){
            return
          }
        }

        // 取出对应id的任务回调,如果正常取出就执行回调
        const task=this.$store.state.taskMapping[res.taskid];
        // 执行回调并清理执行结束的任务回调对象
        if(task){
          task(res);
          this.$store.commit("DELETE_TASK",res.taskid)
        }else{
          this.$message({
            message: '发现空的任务,服务异常',
            type: 'warning'
          });
        }
      
      }

      // WebSocket连接关闭的处理函数
      this.socket.onclose = () => {
        this.$message({
          message: 'websocket连接断开,请刷新页面',
          type: 'error'
        });
        console.log('WebSocket连接已关闭');
      };

      // WebSocket连接发生错误的处理函数
      this.socket.onerror = (err) => {
        console.error('WebSocket连接发生错误:', err);
      };
    }else{
      this.$message({
          message: '浏览器不支持websocket,无法提供服务',
          type: 'error'
        });
    }
  },


}
</script>

<style scoped>
.update-info-button:hover{
    cursor: pointer;
}
.update-info-button{
    display: flex; 
    justify-content: center; /* 水平居中 */
    align-items: center; /* 垂直居中 */
    width: 5.5vw;
    height: 2.5vw;
    font-size: 1vw;
    border-radius: 5px;
    color: #ffffff; 
    background-color: #35d750;
    margin: 5% 0% 0% 10%;
}
.search-data-head-name{
    width: 18vw;
    height: 20vh;
    margin-left: 5%;

}
.search-data-head-image{
    background-size: cover;
    background-repeat: no-repeat;
    width: 10vw;
    height: 20vh;
    border-radius: 10px;
    margin-left: 5%;
}
.image-item:hover{
  cursor: pointer;
  border: 3px solid #d5dbcd;
}
.image-item{
  border-radius: 25px;
  background-color: #ffffff;
  width: 60%; 
  height: 6%;
  margin: 35% 0% 0% 18%;
  border: 3px solid  #ffffff;
}
.image-head{
  border-radius: 5px;
  width: 75%; 
  height: 8%;
  margin: 20% 0% 0% 13%;
}
.left-main{
  width: 5vw;
  height: 100vh;
}
.right-main{
  margin: 4vh 0vh 0vh 1vw;
  border-radius: 30px 30px 0px 30px;
  width: 94vw;
  height: 95.5vh;
  background-color: #F5F6FA;
}

</style>